﻿/**
 * Copyright (C) 2011 original author and authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections.ObjectModel;
using System.Diagnostics;

namespace NGuice.Inject.Internal.Util
{
    /// <summary>
    /// 提供调用代码行的访问
    /// </summary>
    public sealed class SourceProvider
    {
        /// <summary>
        /// 源未知
        /// </summary>
        public static readonly object UNKNOWN_SOURCE = "[unknown source]";
        
        private readonly ICollection<string> classNamesToSkip;
        
        public static readonly SourceProvider DEFAULT_INSTANCE = new SourceProvider(typeof(SourceProvider).FullName);

        private SourceProvider(IEnumerable<string> classesToSkip) {
            string[] clazz = new string[classesToSkip.Count()];
            classesToSkip.ToArray().CopyTo(clazz, 0);
            this.classNamesToSkip = new ReadOnlyCollection<string>(clazz.ToList());
        }

        private SourceProvider(params string[] classesToSkip):this(classesToSkip.AsEnumerable())
        {
        }

        public SourceProvider PlusSkippedClasses(params Type[] moreClassesToSkip) 
        {
            return new SourceProvider(classNamesToSkip.Concat(AsStrings(moreClassesToSkip)));
        }

        private static IList<string> AsStrings(params Type[] classes)
        {
            IList<string> strings = new List<string>();
            foreach (Type c in classes)
            {
                strings.Add(c.FullName);
            }
            return strings;
        }
        
        public StackFrame Get() {
            StackTrace st = new StackTrace(true);
            foreach (StackFrame element in st.GetFrames())
            {
                string className = element.GetMethod().DeclaringType.FullName;
                if (!classNamesToSkip.Contains(className))
                {
                    return element;
                }
            }
            Trace.Fail("source provider error");
            return null;
        }
    }
}
